package love.yuanmengrobot.zframe.mvc;

import com.google.gson.GsonBuilder;
//import love.love.yuanmengrobot.zframe.ioc.BeanFactory;
import love.yuanmengrobot.zframe.ioc.BeanFactoryTest;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class DispatcherServlet extends HttpServlet {


    Map<String, ControllerMapping> controllerMapping;

    @Override
    public void init(ServletConfig config) throws ServletException {
//        System.out.println("开始1");
        BeanFactoryTest.getInstance();
//        System.out.println("开始2");
        controllerMapping = (Map<String, ControllerMapping>) config.getServletContext().getAttribute("love.yuanmengrobot.web.controller");
        /*
        对HashMap进行遍历
         */
//        System.out.println(controllerMapping);
    }


    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ControllerMapping mapping = null;
        String requestURI = request.getRequestURI();
        System.out.println("请求地址：" + requestURI+":"+ request.getContextPath());
        requestURI = StringUtils.substringBetween(requestURI, request.getContextPath(), ".do");
        System.out.println("去掉前缀和后缀：" + requestURI);
        if (controllerMapping.containsKey(requestURI)) {
            mapping = controllerMapping.get(requestURI);
        } else {

        }

        Class controllerClass = mapping.getControllerClass();
        Method handleMethod = mapping.getHandleMethod();
//        System.out.println("------------方法名字：" + handleMethod.getName());
        Class[] parameterType = handleMethod.getParameterTypes();

        /*
        反射获取参数的名称
         */
        List<String> paramterList = new ArrayList<String>();
        Parameter[] params = handleMethod.getParameters();
        for (Parameter parameter : params) {
//            System.out.println("参数名字：" + parameter.getName());

            paramterList.add(parameter.getName());
        }

        Object[] parameterValues = new Object[parameterType.length];
        Object obj = null;
        try {
            String controllerClassName = controllerClass.getSimpleName();
            controllerClassName = StringUtils.replaceChars(controllerClassName, controllerClassName.substring(0, 1), controllerClassName.substring(0, 1).toLowerCase());

//            System.out.println("向工厂申请：" + controllerClassName);
            obj = BeanFactoryTest.getInstance().getBean(controllerClassName);
//            System.out.println("申请完毕" + obj.getClass().getName());
//             obj = controllerClass.newInstance();
            for (int i = 0; i < parameterType.length; i++) {

                if (ClassUtils.isAssignable(parameterType[i], HttpServletRequest.class)) {
                    parameterValues[i] = request;
                } else if (ClassUtils.isAssignable(parameterType[i], HttpServletResponse.class)) {
                    parameterValues[i] = response;
                } else if (ClassUtils.isAssignable(parameterType[i], HttpSession.class)) {
                    parameterValues[i] = request.getSession();
                } else if (parameterType[i].isPrimitive()) {
                    if (parameterType[i].getTypeName().equals("int")) {
                        parameterValues[i] = Integer.parseInt(request.getParameter(paramterList.get(i)));
                    } else if (parameterType[i].getTypeName().equals("float")) {
                        parameterValues[i] = Float.parseFloat(request.getParameter(paramterList.get(i)));
                    }
                } else if (ClassUtils.isAssignable(parameterType[i], String.class)) {
                    System.out.println("String:" + request.getParameter(paramterList.get(i)));
                    parameterValues[i] = request.getParameter(paramterList.get(i));
                } else {
                    //Bean
                    Object pojo = parameterType[i].newInstance();
                    //得到请求里所有的参数：Map<参数名, value>
                    //获取表单里的数据
                    Map<String, String[]> parameterMap = request.getParameterMap();
                    //beanutils会自动将map里的key与bean的属性名进行反射赋值
                    BeanUtils.populate(pojo, parameterMap);
                    parameterValues[i] = pojo;
                }
            }
            /*
            通过反射调用方法，并且把参数的值赋值给
             */
            Object returnValue = handleMethod.invoke(obj, parameterValues);

            if (returnValue != null && returnValue instanceof String) { //方法返回的是一个字符串类
                String path = returnValue.toString();
                if (StringUtils.startsWith(path, "redirect:")) {
                    //重定向
                    response.sendRedirect(request.getContextPath() + StringUtils.substringAfter(path, "redirect:"));
                    System.out.println("新目标1："+request.getContextPath() + StringUtils.substringAfter(path, "redirect:"));
                } else {
                    //转发
                    request.getRequestDispatcher(path).forward(request, response);
                    System.out.println("新目标2："+path);
                }
            } else if (returnValue != null && !(returnValue instanceof String)) {
                response.setContentType("application/json; charset=UTF-8");
                //返回的是一个bean，即客户端发送的是ajax请求，并将该bean转换成json
                String json = new GsonBuilder()
                        .setDateFormat("yyyy-MM-dd HH:mm:ss")
                        .setPrettyPrinting()
                        .create()
                        .toJson(returnValue);
                PrintWriter out = response.getWriter();
                out.write(json);
                out.flush();
                out.close();
                int index=json.indexOf("\"code\":")+8;
                String result=json.substring(index, index+2);
                System.out.println("操作结果："+result);
                boolean ma = transactionFind(handleMethod.getName());
                if("-1".equals(result)&& ma){//-1表示失败 + ma=true表意：add、update等事务操作失败，则回滚吧
//                    System.out.println("----------------发生异常,需要回滚------------------");
                    BeanFactoryTest.getInstance().sqlSession.rollback();
                }else if(ma){//ma=true表意：add、update等事务操作成功
//                    System.out.println("-----------------------无异常，提交事务---------------------------");
                        BeanFactoryTest.getInstance().sqlSession.commit();//提交
                }else {
//                    System.out.println("-----------------------事务没有修改数据库，不提交---------------------------");
                }
            }
        }catch (InstantiationException e) {

            e.printStackTrace();
        } catch (IllegalAccessException e) {

            e.printStackTrace();
        } catch (InvocationTargetException e) {

            e.printStackTrace();
        }

        BeanFactoryTest.getInstance().sqlSession.rollback();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    public boolean transactionFind(String methodName) {
        if (methodName == null) return false;
        SAXReader reader = new SAXReader();
        InputStream in = null;
        Document doc = null;
        List<Element> list;
        try {
            in = Class.forName("love.yuanmengrobot.zframe.mvc.DispatcherServlet")
                    .getResourceAsStream("/transaction.xml");
            doc = reader.read(in);
            list = doc.selectNodes("/beans/bean");
            for (Element e : list) {
                String id = e.attributeValue("id");
                if (id == null) continue;
                if ("method".equals(id)) {
                    List<Element> childElements = e.elements();//得到ele的子元素集合
                    String methodNameMatching = null;
                    for (Element childEle : childElements) {
                        methodNameMatching = childEle.attributeValue("name");
                        methodNameMatching = methodNameMatching.replace("*", "");
//                        System.out.println("裁剪结果:" + methodNameMatching+":"+methodName);
                        if (methodName.startsWith(methodNameMatching)&& childEle.attributeValue("commit").equals("true")) return true;
                    }
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return false;
    }
}
